/*
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
 * Copyright (c) 1996,1999 by Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *	  src/port/inet_net_ntop.c
 */

#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $";
#endif

#ifndef FRONTEND
#include "postgres.h"
#else
#include "postgres_fe.h"
#endif

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#ifndef FRONTEND
#include "utils/inet.h"
#else
/*
 * 在前端构建中，我们无法包含inet.h，但仍然需要对这两个常量有合理的定义。 注意pg_inet_net_ntop()假设PGSQL_AF_INET等于AF_INET。
 */
#define PGSQL_AF_INET	(AF_INET + 0)
#define PGSQL_AF_INET6	(AF_INET + 1)
#endif


#define NS_IN6ADDRSZ 16
#define NS_INT16SZ 2

#ifdef SPRINTF_CHAR
#define SPRINTF(x) strlen(sprintf/**/x)
#else
#define SPRINTF(x) ((size_t)sprintf x)
#endif

static char *fc_inet_net_ntop_ipv4(const u_char *fc_src, int fc_bits,
								char *fc_dst, size_t fc_size);
static char *fc_inet_net_ntop_ipv6(const u_char *fc_src, int fc_bits,
								char *fc_dst, size_t fc_size);


/*
 * char *
 * pg_inet_net_ntop(af, src, bits, dst, size)
 *	将主机/网络地址从网络格式转换为表示格式。
 *	"src"的大小由其"af"确定。
 * 返回:
 *	指向dst的指针，如果发生错误则为NULL（请检查errno）。
 * 注意:
 *	192.5.5.1/28具有非零主机部分，这意味着它不是pg_inet_net_pton()所要求的网络，但可以是包含网络掩码的主机地址。
 * 作者:
 *	Paul Vixie（ISC），1998年10月
 */
char * pg_inet_net_ntop(int fc_af, const void *fc_src, int fc_bits, char *fc_dst, size_t fc_size)
{
	/*
	 * 我们需要涵盖PG inet类型使用的地址族常量（PGSQL_AF_INET和PGSQL_AF_INET6）和系统库使用的那些（AF_INET和AF_INET6）。 我们可以安全地假设PGSQL_AF_INET == AF_INET，但INET6常量很可能会不同。如果AF_INET6未定义，则静默忽略它。
	 */
	switch (fc_af)
	{
		case PGSQL_AF_INET:
			return (fc_inet_net_ntop_ipv4(fc_src, fc_bits, fc_dst, fc_size));
		case PGSQL_AF_INET6:
#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
		case AF_INET6:
#endif
			return (fc_inet_net_ntop_ipv6(fc_src, fc_bits, fc_dst, fc_size));
		default:
			errno = EAFNOSUPPORT;
			return (NULL);
	}
}

/*
 * static char *
 * inet_net_ntop_ipv4(src, bits, dst, size)
 *	将IPv4网络地址从网络格式转换为表示格式。
 *	"src"的大小由其"af"确定。
 * 返回:
 *	指向dst的指针，如果发生错误则为NULL（请检查errno）。
 * 注意:
 *	假定网络字节顺序。这意味着192.5.5.240/28在其第四个八位字节中具有0b11110000。
 * 作者:
 *	Paul Vixie（ISC），1998年10月
 */
static char * fc_inet_net_ntop_ipv4(const u_char *fc_src, int fc_bits, char *fc_dst, size_t fc_size)
{
	char	   *fc_odst = fc_dst;
	char	   *fc_t;
	int			fc_len = 4;
	int			fc_b;

	if (fc_bits < 0 || fc_bits > 32)
	{
		errno = EINVAL;
		return (NULL);
	}

	/* 始终格式化所有四个八位字节，无论掩码长度如何。 */
	for (fc_b = fc_len; fc_b > 0; fc_b--)
	{
		if (fc_size <= sizeof ".255")
			goto emsgsize;
		fc_t = fc_dst;
		if (fc_dst != fc_odst)
			*fc_dst++ = '.';
		fc_dst += SPRINTF((fc_dst, "%u", *fc_src++));
		fc_size -= (size_t) (fc_dst - fc_t);
	}

	/* 如果32位，则不打印masklen */
	if (fc_bits != 32)
	{
		if (fc_size <= sizeof "/32")
			goto emsgsize;
#ifdef FDD //cppcheck
		fc_dst += SPRINTF((fc_dst, "/%d", fc_bits));
#else
		fc_dst += SPRINTF((fc_dst, "/%u", fc_bits));
#endif
	}

	return (fc_odst);

emsgsize:
	errno = EMSGSIZE;
	return (NULL);
}

static int fc_decoct(const u_char *fc_src, int fc_bytes, char *fc_dst, size_t fc_size)
{
	char	   *fc_odst = fc_dst;
	char	   *fc_t;
	int			fc_b;

	for (fc_b = 1; fc_b <= fc_bytes; fc_b++)
	{
		if (fc_size <= sizeof "255.")
			return (0);
		fc_t = fc_dst;
		fc_dst += SPRINTF((fc_dst, "%u", *fc_src++));
		if (fc_b != fc_bytes)
		{
			*fc_dst++ = '.';
			*fc_dst = '\0';
		}
		fc_size -= (size_t) (fc_dst - fc_t);
	}
	return (fc_dst - fc_odst);
}

static char * fc_inet_net_ntop_ipv6(const u_char *fc_src, int fc_bits, char *fc_dst, size_t fc_size)
{
	/*
	 * 注意，int32_t和int16_t仅需"至少"足够大以容纳指定大小的值。在一些系统上，如Cray，并不存在16位的整数变量。如果您认为此函数应该已被编码为使用指针叠加，请记住这一点。全世界并非都是VAX。
	 */
	char		fc_tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
	char	   *fc_tp;
	struct
	{
		int			base,
					len;
	}			fc_best, fc_cur;
	u_int		fc_words[NS_IN6ADDRSZ / NS_INT16SZ];
	int			fc_i;

	if ((fc_bits < -1) || (fc_bits > 128))
	{
		errno = EINVAL;
		return (NULL);
	}

	/*
	 * 预处理：将输入（按字节）数组复制到按字处理数组中。在src[]中找到最长的0x00的连续运行以进行::简化。
	 */
	memset(fc_words, '\0', sizeof fc_words);
	for (fc_i = 0; fc_i < NS_IN6ADDRSZ; fc_i++)
		fc_words[fc_i / 2] |= (fc_src[fc_i] << ((1 - (fc_i % 2)) << 3));
	fc_best.base = -1;
	fc_cur.base = -1;
	fc_best.len = 0;
	fc_cur.len = 0;
	for (fc_i = 0; fc_i < (NS_IN6ADDRSZ / NS_INT16SZ); fc_i++)
	{
		if (fc_words[fc_i] == 0)
		{
			if (fc_cur.base == -1)
				fc_cur.base = fc_i, fc_cur.len = 1;
			else
				fc_cur.len++;
		}
		else
		{
			if (fc_cur.base != -1)
			{
				if (fc_best.base == -1 || fc_cur.len > fc_best.len)
					fc_best = fc_cur;
				fc_cur.base = -1;
			}
		}
	}
	if (fc_cur.base != -1)
	{
		if (fc_best.base == -1 || fc_cur.len > fc_best.len)
			fc_best = fc_cur;
	}
	if (fc_best.base != -1 && fc_best.len < 2)
		fc_best.base = -1;

	/*
	 * 格式化结果。
	 */
	fc_tp = fc_tmp;
	for (fc_i = 0; fc_i < (NS_IN6ADDRSZ / NS_INT16SZ); fc_i++)
	{
		/* 我们是在最佳的0x00的连续运行内吗？ */
		if (fc_best.base != -1 && fc_i >= fc_best.base &&
			fc_i < (fc_best.base + fc_best.len))
		{
			if (fc_i == fc_best.base)
				*fc_tp++ = ':';
			continue;
		}
		/* 我们是在0x00或任何真实十六进制的初始运行之后吗？ */
		if (fc_i != 0)
			*fc_tp++ = ':';
		/* 此地址是封装的IPv4吗？ */
		if (fc_i == 6 && fc_best.base == 0 && (fc_best.len == 6 ||
										 (fc_best.len == 7 && fc_words[7] != 0x0001) ||
										 (fc_best.len == 5 && fc_words[5] == 0xffff)))
		{
			int			fc_n;

			fc_n = fc_decoct(fc_src + 12, 4, fc_tp, sizeof fc_tmp - (fc_tp - fc_tmp));
			if (fc_n == 0)
			{
				errno = EMSGSIZE;
				return (NULL);
			}
			fc_tp += strlen(fc_tp);
			break;
		}
		fc_tp += SPRINTF((fc_tp, "%x", fc_words[fc_i]));
	}

	/* 这是一个尾部的0x00的连续运行吗？ */
	if (fc_best.base != -1 && (fc_best.base + fc_best.len) ==
		(NS_IN6ADDRSZ / NS_INT16SZ))
		*fc_tp++ = ':';
	*fc_tp = '\0';

	if (fc_bits != -1 && fc_bits != 128)
#ifdef FDD //cppcheck
		fc_tp += SPRINTF((fc_tp, "/%d", fc_bits));
#else
		tp += SPRINTF((tp, "/%u", bits));
#endif
	/*
	 * 检查溢出，复制，我们就完成了。
	 */
	if ((size_t) (fc_tp - fc_tmp) > fc_size)
	{
		errno = EMSGSIZE;
		return (NULL);
	}
	strcpy(fc_dst, fc_tmp);
	return (fc_dst);
}
